package com.xinsoft.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinsoft.common.Response;
import com.xinsoft.common.exception.BDException;
import com.xinsoft.constant.Const;
import com.xinsoft.entity.dto.*;
import com.xinsoft.entity.po.*;
import com.xinsoft.service.*;
import com.xinsoft.mapper.MesProcessPlanMapper;
import com.xinsoft.utils.TokenUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* @author hsm
* @description 针对表【mes_process_plan(工序计划)】的数据库操作Service实现
* @createDate 2023-09-13 15:26:38
*/
@Service
public class MesProcessPlanServiceImpl extends ServiceImpl<MesProcessPlanMapper, MesProcessPlan>
    implements MesProcessPlanService{

    @Resource
    public SysDocumentNumService sysDocumentNumService;

    @Resource
    public MesProcessPlanDetailService mesProcessPlanDetailService;

    @Resource
    public MesProcessPlanService mesProcessPlanService;

    @Resource
    public MesDispatchService mesDispatchService;

    @Resource
    public MesProcessDetailTeamUserRefService mesProcessDetailTeamUserRefService;

    @Resource
    public MesProcessDetailDeviceRefService mesProcessDetailDeviceRefService;

    @Resource
    public MesDocumentService mesDocumentService;

    @Resource
    public SysFileHisService fileHisService;

    @Override
    public IPage<MesProcessPlanDTO> findPageListByParam(MesProcessPlanParam param) {
        //分页
        Page<MesProcessPlanDTO> page = new Page<MesProcessPlanDTO>(param.getCurrentPage(), param.getPageSize());
        IPage<MesProcessPlanDTO> resultPage = this.baseMapper.findListByParam(page, param);
        //返回值
        return resultPage;
    }

    @Override
    public MesProcessPlanDTO findTotalByParam(MesProcessPlanParam param) {
        MesProcessPlanDTO total = this.baseMapper.findTotalByParam(param);
        //返回值
        return total;
    }


    @Override
    public MesProcessPlanDTO getInfoById(Integer id) {
        MesProcessPlanDTO planDTO = this.baseMapper.findInfoById(id);
        planDTO.setMesProcessPlanDetailList(mesProcessPlanDetailService.getMesProcessPlanDetailListByPlanId(id));
        return planDTO;
    }

    @Override
    public void edit(MesProcessPlanDTO planDTO) {
        // 更新计划
        MesProcessPlan plan = new MesProcessPlan();
        BeanUtils.copyProperties(planDTO,plan);
        updateById(plan);

        // 更新明细
        List<MesProcessPlanDetail> details = new ArrayList<>();
        for (MesProcessPlanDetailDTO detailDTO : planDTO.getMesProcessPlanDetailList()) {
            mesProcessPlanDetailService.edit(detailDTO);
        }
    }

    @Override
    public void add(MesProcessPlanDTO planDO) {
        MesProcessPlan plan = new MesProcessPlan();
        BeanUtils.copyProperties(planDO,plan);
        if (CollectionUtils.isEmpty(planDO.getMesProcessPlanDetailList())) {
            throw new BDException("工序明细不能为空");
        }
        //生成工单编号
        plan.setProcessNo(sysDocumentNumService.getSysDocumentNumByDocumentId(Const.DOCUMENT_ID.MES_PROCESS_PLAN_DOCUMENT));
        sysDocumentNumService.incrementLastSerialByDocumentId(Const.DOCUMENT_ID.MES_PROCESS_PLAN_DOCUMENT);
        // 设置计划状态
        plan.setProcessStatus(Const.producePlanStatus.PLAN);

        // 设置未首检
        plan.setDoFirstInspection(0);
        //保存主表
        save(plan);
        Integer planId = plan.getId();


        for (MesProcessPlanDetailDTO detailDO : planDO.getMesProcessPlanDetailList()) {

            List<MesProcessDetailTeamUserRef> mesProcessDetailTeamUserRefList = new ArrayList<>();
            List<MesProcessDetailDeviceRef> mesProcessDetailDeviceRefList = new ArrayList<>();
            // 未派工
            detailDO.setDoDispatching(Const.producePlanStatus.UN_DISPATCHED);
            detailDO.setProcessPlanId(planId);
            detailDO.setAlreadyCount(BigDecimal.ZERO);
            detailDO.setPlanCount(plan.getPlanNum());
            // 保存明细行
            mesProcessPlanDetailService.save(detailDO);
            Integer detailId = detailDO.getId();

            // 根据工艺工序id获取 工艺工序下的班组list
            mesProcessDetailTeamUserRefList.addAll(this.baseMapper.getMesProcessDetailTeamUserRef(detailDO.getCraftProcessId(), detailId));
            // 根据工艺工序id和工序id获取 工序下的设备list
            mesProcessDetailDeviceRefList.addAll(this.baseMapper.getMesProcessDetailDeviceRef(detailDO.getCraftProcessId(), detailId));

            if(CollectionUtils.isEmpty(mesProcessDetailTeamUserRefList)){
                throw new BDException("操作失败，请配置工序："+detailDO.getProcessName()+"的工艺工序的班组!");
            }
//            if(CollectionUtils.isEmpty(mesProcessDetailDeviceRefList)){
//                throw new BDException("操作失败，请配置工艺工序的设备组!");
//            }

            // 保存 班组关系
            mesProcessDetailTeamUserRefService.saveBatch(mesProcessDetailTeamUserRefList);
            // 保存 设备组关系
            if(ObjectUtil.isNotEmpty(mesProcessDetailDeviceRefList)){
            mesProcessDetailDeviceRefService.saveBatch(mesProcessDetailDeviceRefList);
            }
            // 保存检验方案





            // 根据工艺工序id 获取sop文件
            List<SysFileHis> sysFileHisList = null;
            List<MesDocument> documentList = mesDocumentService.list(new QueryWrapper<MesDocument>()
                    .eq("mes_type", 2)
                    .eq("mes_id", detailDO.getCraftProcessId()));
            List<Integer> fileIds = new ArrayList<>();
            for (MesDocument mesDocument : documentList) {
                fileIds.add(mesDocument.getDocumentId());
            }
            if (documentList.size() > 0) {
                sysFileHisList = fileHisService.listByIds(fileIds);
            }

            //保sop
            if (!CollectionUtils.isEmpty(sysFileHisList)) {
                List<MesDocument> mesDocumentList = new ArrayList<>();
                for (SysFileHis sysFileHis : sysFileHisList) {
                    MesDocument mesDocument = new MesDocument();
                    mesDocument.setMesId(detailId);
                    mesDocument.setDocumentId(sysFileHis.getId());
                    mesDocument.setMesType(2);
                    mesDocumentList.add(mesDocument);
                }
                mesDocumentService.saveBatch(mesDocumentList);
            }
        }

    }

    @Override
    public void del(List<Integer> ids) {
        // 删除
        removeByIds(ids);
    }

    /**
     *  华德是否要根据明细表do_auto字段判断是否自动派工
     *  自动派工生成的派工单默认开工还是挂起-do_dispatching
     * @param ids
     */
    @Override
    public Response<?> issuedPlans(List<Integer> ids) {

        List<MesProcessPlanDetail> planDetailDOS = mesProcessPlanDetailService.list(new LambdaQueryWrapper<MesProcessPlanDetail>().in(MesProcessPlanDetail::getProcessPlanId, ids));
        Map<Integer, MesProcessPlanDetail> planDetailMapById = planDetailDOS.stream().collect(Collectors.toMap(item -> item.getId(), Iterable -> Iterable, (v1, v2) -> v1));
        List<Integer> planDetailIds = planDetailDOS.stream().map(MesProcessPlanDetail::getId).collect(Collectors.toList());
        List<Integer> processPlanIds = planDetailDOS.stream().map(MesProcessPlanDetail::getProcessPlanId).collect(Collectors.toList());
        List<MesProcessPlan> processPlanDOS = mesProcessPlanService.list(new LambdaQueryWrapper<MesProcessPlan>().in(MesProcessPlan::getId, processPlanIds));
        Map<Integer, MesProcessPlan> processPlanMap = processPlanDOS.stream().collect(Collectors.toMap(item -> item.getId(), Iterable -> Iterable, (v1, v2) -> v1));


        // 修改子表、主表状态
        ArrayList<MesProcessPlan> mesProcessPlans = new ArrayList<>();
        Date nowDate = new Date();
        planDetailDOS.forEach(item -> {
            item.setDoDispatching(Const.producePlanStatus.DISPATCHED);
            MesProcessPlan mesProcessPlan = new MesProcessPlan();
            mesProcessPlan.setId(item.getProcessPlanId());
            mesProcessPlan.setProcessStatus(Const.producePlanStatus.ISSUED);
            mesProcessPlan.setAssignId(TokenUtil.getUserId());
            mesProcessPlan.setAssignTime(nowDate);
            mesProcessPlans.add(mesProcessPlan);
        });
        mesProcessPlanDetailService.updateBatchById(planDetailDOS);
        mesProcessPlanService.saveOrUpdateBatch(mesProcessPlans);

//        List<MesProcessDetailDeviceRef> deviceRefDOS = mesProcessDetailDeviceRefService.list(new LambdaQueryWrapper<MesProcessDetailDeviceRef>().in(MesProcessDetailDeviceRef::getProcessPlanDetailId, planDetailIds));
//        Map<Integer, List<MesProcessDetailDeviceRef>> deviceRefGroupByProcessDetail = deviceRefDOS.stream().collect(Collectors.groupingBy(MesProcessDetailDeviceRef::getProcessPlanDetailId));

        // 生成派工单
        List<MesProcessDetailTeamUserRef> teamRefsDOS = mesProcessDetailTeamUserRefService.list(new LambdaQueryWrapper<MesProcessDetailTeamUserRef>().in(MesProcessDetailTeamUserRef::getProcessPlanDetailId, planDetailIds));
        Map<Integer, MesProcessDetailTeamUserRef> teamRefsMapByTeamId = teamRefsDOS.stream().collect(Collectors.toMap(item -> item.getProcessPlanDetailId(), Iterable -> Iterable, (v1, v2) -> v1));
        if (teamRefsMapByTeamId.size() != planDetailIds.size()){
            return Response.fail("工序计划未维护班组");
        }


        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("document_id",Const.DOCUMENT_ID.MES_DISPATCH);
        SysDocumentNum sysDocumentNum = sysDocumentNumService.getOne(queryWrapper);

        //这个操作是为了去重：同一个工序计划、班组只保留一条记录
        Map<String, List<MesProcessDetailTeamUserRef>> teamRefsMapByProcessTeam = teamRefsDOS.stream().
                collect(Collectors.groupingBy(item -> item.getProcessPlanDetailId() + "-" + item.getTeamId()));
        List<MesDispatch> dispatchList = teamRefsMapByProcessTeam.keySet().stream().map(item -> {
            List<MesProcessDetailTeamUserRef> teamUserRefs = teamRefsMapByProcessTeam.get(item);
            MesProcessPlanDetail planDetail = planDetailMapById.get(teamUserRefs.get(0).getProcessPlanDetailId());
            MesProcessPlan processPlan = processPlanMap.get(planDetail.getProcessPlanId());
//            List<MesProcessDetailDeviceRef> deviceRefList = deviceRefGroupByProcessDetail.get(planDetail.getId());
            MesDispatch mesDispatch = new MesDispatch();
            mesDispatch.setProcessPlanDetailId(planDetail.getId());
            mesDispatch.setDispatchCode(sysDocumentNumService.generatorDispatchCodeCode(sysDocumentNum));
            sysDocumentNum.setLastSerial(sysDocumentNum.getLastSerial() + 1);
            mesDispatch.setTeamId(teamUserRefs.get(0).getTeamId());
            mesDispatch.setDeviceId("[]");
//            mesDispatch.setDeviceId(ObjectUtil.isEmpty(deviceRefList) ? "[]" :
//                    JSON.toJSONString(deviceRefList.stream().map(MesProcessDetailDeviceRef::getDeviceId).distinct().collect(Collectors.toList())));
            mesDispatch.setStartTime(processPlan.getPlanStartTime());
            mesDispatch.setOperator("[]");
            mesDispatch.setOperatorDevicesBind("[]");
            mesDispatch.setOperatorInit(JSON.toJSONString(teamUserRefs.stream().map(MesProcessDetailTeamUserRef::getUserId).collect(Collectors.toList())));
            mesDispatch.setEndTime(processPlan.getPlanEndTime());
            mesDispatch.setPlanNum(planDetail.getPlanCount());
            mesDispatch.setDispatchStatus(Const.PlanType.dai_chan);
            mesDispatch.setCompleteNum(BigDecimal.ZERO);
            mesDispatch.setRemark("");
            return mesDispatch;
        }).collect(Collectors.toList());
        sysDocumentNumService.updateById(sysDocumentNum);
        mesDispatchService.saveBatch(dispatchList);
        return Response.succeed();

    }

    @Override
    public void reverseIssuedPlan(List<Integer> ids) {
        for (Integer id : ids) {
            MesProcessPlan processPlan = this.getById(id);

            // 非待产不允许反下达
            // 获取详情id
            List<MesProcessPlanDetail> detailList = mesProcessPlanDetailService.list(new QueryWrapper<MesProcessPlanDetail>().eq("process_plan_id",id));

            List<Integer> detailIds = detailList.stream().map(MesProcessPlanDetail::getId).collect(Collectors.toList());
            List<MesDispatch> mesDispatchList = mesDispatchService.list(new QueryWrapper<MesDispatch>().in("process_plan_detail_id",detailIds).ne("dispatch_status",Const.PlanType.dai_chan));

            if(!CollectionUtils.isEmpty(mesDispatchList)) {
                throw new BDException("操作失败，工序计划：" + processPlan.getProcessNo() + "已经生产，不能反下达！");
            }

            processPlan.setProcessStatus(Const.producePlanStatus.PLAN);
            processPlan.setAssignId(null);
            processPlan.setAssignTime(null);
            updateById(processPlan);
        }
    }

    @Override
    public void close(List<Integer> ids) {
        for (Integer id : ids) {
            MesProcessPlan processPlan = this.getById(id);
            processPlan.setProcessStatus(Const.producePlanStatus.CLOSE_CASE);
            updateById(processPlan);
        }
    }

    @Override
    public void reverseClose(List<Integer> ids) {
        for (Integer id : ids) {
            MesProcessPlan processPlan = this.getById(id);
            processPlan.setProcessStatus(Const.producePlanStatus.PLAN);
            updateById(processPlan);
        }
    }
}




